#ifndef _POLYNOMIAL_H
#define _POLYNONIAL_H

#pragma once

#include <iostream>
#include <math.h>
#include <vector>
#include <string.h>
#include <limits>

using namespace std;

class Polynomial
{
    private:
    int deg = 0;             //degree of polynomial
    std::vector<double> coef = {0};  //顺序为a0-an

    public:
    Polynomial(){}
    Polynomial(std::vector<double> _coef)
    {
        deg = _coef.size() - 1;
        coef = _coef;
    }
    Polynomial(double c)  //常数多项式
    {
        std::vector<double> _coef = {c};
        coef = _coef;
        deg = 0;
    }
    Polynomial(double a,double b)   //一次多项式a+bx,a为常数项系数
    {
        std::vector<double> _coef = {a,b};
        coef = _coef;
        deg = 1;
    }

    ~Polynomial()
    {
        coef.clear();
    }

    int show_deg()
    {
        return deg;
    }

    void show_coef()
    {
        for (int i = 0; i <= deg; i++)
        {
            std::cout << coef[i] << "\t" ;
        }
        std::cout << std::endl;
        
    }

    double operator()(double x)
    {
        double ret = coef[deg];
        for (int i = deg; i > 0; i--)
        {
            ret = ret * x + coef[i-1];
        }
        return ret;
    }

    Polynomial operator+(Polynomial q)
    {
        int newdeg;
        if (deg > q.deg)
        {
            newdeg = deg;
            vector<double> newcoef(coef);
            for (int i = 0; i <= q.deg; i++)
            {
                newcoef[i] += q.coef[i];
            }
            Polynomial newpoly(newcoef);
            return newpoly;
        }
        else
        {
            newdeg = q.deg;
            vector<double> newcoef(q.coef);
            for (int i = 0; i <= deg; i++)
            {
                newcoef[i] += coef[i];
            }
            Polynomial newpoly(newcoef);
            return newpoly;
        }
    }

    Polynomial operator*(Polynomial q)
    {
        int newdeg = deg + q.deg;
        std::vector<double> newcoef(newdeg + 1);
        for (int k = 0; k <= newdeg; k++)
        {
            double c = 0;
            for (int i = 0; i <= deg; i++)
            {
                int j = k - i;
                if (j >= 0 && j <= q.deg)
                {
                    c += coef[i] * q.coef[j];
                }
            }
            newcoef[k] = c;
        }

        Polynomial newpoly(newcoef);
        return newpoly;
    }

    Polynomial operator*(double a)
    {
        std::vector<double> newcoef(coef);
        for (int k = 0; k <= deg; k++)
        {
            newcoef[k] *= a;
        }

        Polynomial newpoly(newcoef);
        return newpoly;
    }

    Polynomial derive()
    {
        if (deg == 0)
        {
            std::vector<double> a = {0};
            Polynomial p(a);
            return p;
        }
        else
        {
            std::vector<double> a(deg);
            for (int i = 0; i < deg; i++)
            {
                a[i] = coef[i+1] * (i + 1);
            }
            Polynomial p(a);
            return p;
        }
    }

    string polystr()
    {
        string str;
        double eps = 1000 * std::numeric_limits<double>::epsilon();
        for (int i = deg; i >= 0; i--)
        {
            if (fabs(coef[i] - 0) < eps )
                continue;

            if (i == deg)
            {
                str.append(to_string(coef[i]));
            }
            else 
            {
                if (coef[i] > 0)
                {
                    str.append("+");
                }
                str.append(to_string(coef[i]));
            }

            if (i > 1)
            {
                str.append("x^");
                str.append(to_string(i));
            }else if(i == 1)
            {
                str.append("x");
            }
        }
        return str;
    }
    
    void show_poly()
    {
        std::cout << polystr() << endl;
    }

    void zero() //归零
    {
        std::vector<double> a = {0};
        coef = a;
        deg = 0;
    }
    
};


#endif